{#
 # Copyright (c) 2020 Renata Hodovan, Akos Kiss.
 #
 # Licensed under the BSD 3-Clause License
 # <LICENSE.rst or https://opensource.org/licenses/BSD-3-Clause>.
 # This file may not be copied, modified, or distributed except
 # according to those terms.
 #}

{% macro processVariableNode(node) %}
local_ctx['{{ node.name }}'] = current.last_child
{% endmacro %}


{% macro processActionNode(node) %}
{{ node.src | substitute('\$(?P<var_name>\\w+)', 'local_ctx[\'\\g<var_name>\']') }}
{% endmacro %}


{% macro processLambdaNode(node) %}
pass
{% endmacro %}


{% macro processRuleNode(node) %}
self.{{ node.id }}(parent=current)
{% endmacro %}


{% macro processCharsetNode(node) %}
UnlexerRule(src=self.model.charset(current, {{ node.idx }}, self._charsets[{{ node.charset }}]), parent=current)
{% endmacro %}


{% macro processLiteralNode(node) %}
UnlexerRule(src='{{ node.src }}', parent=current)
{% endmacro %}


{% macro processQuantifierNode(node) %}
if self.max_depth >= {{ 0 if node.min == 1 else node.min_depth }}:
    for _ in self.model.quantify(current, {{ node.idx }}, min={{ node.min }}, max={{ node.max }}):
    {% for child in node.out_neighbours %}
        {{ processNode(child) | indent | indent -}}
    {% endfor %}
{% endmacro %}


{% macro processAlternationNode(node) %}
choice = self.model.choice(current, {{ node.idx }}, [0 if [{{ node.min_depth | join(', ') }}][i] > self.max_depth else w for i, w in enumerate([{{ node.conditions | join(', ') }}])])
{% for child in node.out_neighbours %}
{{ 'if' if loop.index0 == 0 else 'elif' }} choice == {{ loop.index0 }}:
    {{ processNode(child) | indent -}}
{% endfor %}
{% endmacro %}


{% macro processAlternativeNode(node) %}
{% for child in node.out_neighbours %}
{{ processNode(child) -}}
{% endfor %}
{% endmacro %}


{% macro processNode(node) %}
{% set processors = {
    'QuantifierNode': processQuantifierNode,
    'UnlexerRuleNode': processRuleNode,
    'UnparserRuleNode': processRuleNode,
    'ImagRuleNode': processRuleNode,
    'CharsetNode': processCharsetNode,
    'LiteralNode': processLiteralNode,
    'AlternationNode': processAlternationNode,
    'AlternativeNode': processAlternativeNode,
    'ActionNode': processActionNode,
    'LambdaNode': processLambdaNode,
    'VariableNode': processVariableNode,
    }
%}
{{ processors[node.__class__.__name__](node) -}}
{% endmacro %}


# Generated by Grammarinator {{ version }}

from itertools import chain
from math import inf
from grammarinator.runtime import *

{% if graph.superclass != 'Generator' %}
if __name__ is not None and '.' in __name__:
    from .{{ graph.superclass }} import {{ graph.superclass }}
else:
    from {{ graph.superclass }} import {{ graph.superclass }}


{% endif %}

{%- if graph.header %}
{{ graph.header }}
{% endif -%}


class {{ graph.name }}({{ graph.superclass }}):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    {% for rule in graph.imag_rules %}
    def {{ rule.id }}(self, parent=None):
        return UnlexerRule(name='{{ rule.id }}', parent=parent)
    {% endfor %}

    {%- if graph.member %}
    {{ graph.member | trim | indent }}
    {% endif %}

    {% for rule in graph.rules %}
    @depthcontrol
    def {{ rule.id }}(self, parent=None):
        {% if rule.id != 'EOF' %}
        {% if rule.has_var %}
        local_ctx = dict()
        {% endif %}
        current = {{ rule.type }}(name='{{ rule.id }}', parent=parent)
        self.enter_rule(current)
        {% for child in rule.out_neighbours %}
        {{ processNode(child) | indent | indent -}}
        {% endfor %}
        self.exit_rule(current)
        return current
        {% else %}
        pass
        {% endif %}
    {{ rule.id }}.min_depth = {{ rule.min_depth }}

    {% endfor %}
    default_rule = {{ graph.default_rule }}

    _charsets = {
        {% for charset in graph.charsets %}
        {{ charset.id }}: list(chain.from_iterable({{ charset.ranges | substitute('(\(.*?\))', 'range\\1') }})),
        {% endfor %}
    }
{# Ensure newline at end of file #}
